using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    public sealed class ListLiteral : Expression // NOTE: Was internal
    {
        internal readonly List<Expression> Values;

        internal ListLiteral(List<Expression> values)
        {
            Values = values;
            values.TrimExcess();
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            var list = new SimpleSequence(Values.Count);
            foreach (Expression exp in Values)
            {
                ITemplateModel tm = exp.GetAsTemplateModel(env);
                AssertNonNull(tm, exp, env);
                list.Add(tm);
            }
            return list;
        }

        /**
         * For the benefit of method calls, return the list of arguments as a list
         * of values.
         */
        internal IList<string> GetValueList(Environment env)
        {
            int size = Values.Count;
            switch (size)
            {
                case 0:
                    {
                        return new List<string>(0).AsReadOnly();
                    }
                case 1:
                    {
                        return new List<string> {Values[0].GetStringValue(env)}.AsReadOnly();
                    }
                default:
                    {
                        return Values.Select(exp => exp.GetStringValue(env)).ToList();
                    }
            }
        }

        /**
         * For the benefit of extended method calls, return the list of arguments as a
         * list of template models.
         */
        internal IList<ITemplateModel> GetModelList(Environment env)
        {
            int size = Values.Count;
            switch (size)
            {
                case 0:
                    {
                        return new List<ITemplateModel>(0).AsReadOnly();
                    }
                case 1:
                    {
                        return new List<ITemplateModel> {Values[0].GetAsTemplateModel(env)}.AsReadOnly();
                    }
                default:
                    {
                        return Values.Select(exp => exp.GetAsTemplateModel(env)).ToList();
                    }
            }
        }

        public override string GetCanonicalForm()
        {
            var buf = new StringBuilder("[");
            int size = Values.Count;
            for (int i = 0; i < size; i++)
            {
                Expression value = Values[i];
                buf.Append(value.GetCanonicalForm());
                if (i != size - 1)
                {
                    buf.Append(",");
                }
            }
            buf.Append("]");
            return buf.ToString();
        }

        internal override bool IsLiteral()
        {
            if (ConstantValue != null)
            {
                return true;
            }
            return Values.All(exp => exp.IsLiteral());
        }

        // A hacky routine used by VisitNode and RecurseNode

        internal ITemplateSequenceModel EvaluateStringsToNamespaces(Environment env)
        {
            var val = (ITemplateSequenceModel) GetAsTemplateModel(env);
            var result = new SimpleSequence(val.Size());
            for (int i = 0; i < Values.Count; i++)
            {
                if (Values[i] is StringLiteral)
                {
                    string s = ((StringLiteral) Values[i]).GetAsString();
                    try
                    {
                        Environment.Namespace ns = env.ImportLib(s, null);
                        result.Add(ns);
                    }
                    catch (IOException ioe)
                    {
                        throw new TemplateException("Could not import library '" + s + "', " + ioe.Message, env);
                    }
                }
                else
                {
                    result.Add(val.Get(i));
                }
            }
            return result;
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            List<Expression> clonedValues = Values.Select(i => i.DeepClone(name, subst)).ToList();
            return new ListLiteral(clonedValues);
        }
    }
}